use crate::data::log_record::LogRecordPos;
use crate::index::{IndexIterator, Indexer};
use crate::options::{IndexType, IteratorOptions};
use parking_lot::RwLock;
use std::collections::BTreeMap;
use std::ops::Index;
use std::sync::Arc;

pub struct BTree {
    tree: Arc<RwLock<BTreeMap<Vec<u8>, LogRecordPos>>>,
}

impl BTree {
    pub fn new() -> BTree {
        BTree {
            tree: Arc::new(RwLock::new(BTreeMap::new())),
        }
    }
}

impl Indexer for BTree {
    fn put(&self, key: Vec<u8>, pos: LogRecordPos) -> bool {
        let mut write_guard = self.tree.write();
        write_guard.insert(key, pos);
        true
    }

    fn get(&self, key: Vec<u8>) -> Option<LogRecordPos> {
        let read_guard = self.tree.read();
        read_guard.get(&key).copied()
    }

    fn delete(&self, key: Vec<u8>) -> bool {
        let mut write_guard = self.tree.write();
        write_guard.remove(&key).is_some()
    }

    fn iterator(&self,options:IteratorOptions) -> Box<dyn IndexIterator> {
        let read_guard = self.tree.read();
        let mut items = Vec::with_capacity(read_guard.len());
        for (k, v) in read_guard.iter() {
            items.push((k.clone(), v.clone()));
        }
        if options.reverse {
            items.reverse();
        }
        Box::new(
            BTreeIterator {
                items,
                curr_index: 0,
                option:options,
            }
        )
    }
}

// btree 迭代器
pub struct BTreeIterator {
    items:Vec<(Vec<u8>, LogRecordPos)>,  // 存储key+索引
    curr_index:usize, // 当前变量下标
    option: IteratorOptions,
}

impl IndexIterator for BTreeIterator {
    fn rewind(&mut self) {
        self.curr_index = 0;
    }

    fn seek(&mut self, key: Vec<u8>) {
        self.curr_index = match self.items.binary_search_by(|(x,_)| {
            if self.option.reverse {
                x.cmp(&key).reverse()
            } else { x.cmp(&key) }
        }) {
            Ok(index) => {index},
            Err(index) => {index},
        };
    }

    fn next(&mut self) -> Option<(&Vec<u8>, &LogRecordPos)> {
        if self.curr_index >= self.items.len() {
            return None;
        }
        while let Some (item) = self.items.get(self.curr_index) {
            self.curr_index += 1;
            let prefx = &self.option.prefix;
            if prefx.is_empty() || item.0.starts_with(&prefx){
                return Some((&item.0,&item.1));
            }

        }
        None
    }
}




#[cfg(test)]
mod tests {
    use crate::data::log_record::LogRecordPos;
    use crate::index::BTree::BTree;
    use crate::index::Indexer;
    use crate::options::IteratorOptions;

    #[test]
    fn test_btree_put() {
        let btree = BTree::new();
        assert_eq!(
            btree.put(
                "".as_bytes().to_vec(),
                LogRecordPos {
                    file_id: 1,
                    offset: 2
                }
            ),
            true
        );
    }

    #[test]
    fn test_btree_iterator_seek() {
        let btree = BTree::new();

        let mut iter1 = btree.iterator(IteratorOptions::default());
        iter1.seek(b"a".to_vec());
        let res1 = iter1.next();
        println!("{:?}", res1);

        // 有一条数据情况
        btree.put(b"ccde".to_vec(),LogRecordPos{file_id: 2, offset: 3});
        let mut iter2 = btree.iterator(IteratorOptions::default());

        iter2.seek(b"ccde1".to_vec());
        let res2 = iter2.next();
        println!("{:?}", res2);

    }



}
